package uk.co.q3c.deplan.server.unit.domain.resource;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.resource.BaseCalendar;
import uk.co.q3c.deplan.client.domain.resource.DefaultWorkingTime;
import uk.co.q3c.deplan.client.domain.resource.ResourceCalendar;
import uk.co.q3c.deplan.client.service.ServiceFactory;
import uk.co.q3c.deplan.server.Server;
import uk.co.q3c.deplan.server.util.Q3Calendar;

public class ResourceCalendar_UT {
	ServiceFactory connection;
	protected final Logger logger = Logger.getLogger(getClass().getName());
	BaseCalendar baseCalendar;
	ResourceCalendar resourceCalendar1;
	ResourceCalendar resourceCalendar2;

	@BeforeClass
	protected void beforeClass() {
		connection = Server.connection();
	}

	@BeforeMethod
	public void setup() {
		baseCalendar = new BaseCalendar(connection);
		resourceCalendar1 = new ResourceCalendar(connection);
		resourceCalendar1.setBaseCalendar(baseCalendar);
		resourceCalendar2 = new ResourceCalendar(connection);
		resourceCalendar2.setBaseCalendar(baseCalendar);
	}

	@Test
	public void makeAdjustments() throws ParseException {
		// 21 Jan 08 rel -21 should return 450-21 = 429
		Calendar di = new GregorianCalendar();
		di.set(2008, 0, 21);
		baseCalendar.addAdjustment(di.getTime(), false, -20);

		// 22 Jan 08, abs 363
		Calendar cal2 = GregorianCalendar.getInstance();
		cal2.set(2008, 0, 22);
		Date date = cal2.getTime();
		baseCalendar.addAdjustment(date, true, 363);

		// 23 Jan 08 rel +57 should return 450+57 = 507
		baseCalendar.addAdjustment(2008, 0, 23, false, 57);

		// 24 Jan abs 3 mins
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(2008, 0, 24);
		baseCalendar.addAdjustment(cal.getTime(), true, 3);

		Assert.assertEquals(baseCalendar.getAdjustment(di.getTime())
				.getAdjustment(), -20);
		Assert.assertEquals(baseCalendar.getAdjustment(date)
				.getAdjustment(), 363);
		Assert.assertEquals(baseCalendar.getAdjustment(2008, 0, 23)
				.getAdjustment(), 57);
		Assert.assertEquals(baseCalendar.getAdjustment(cal.getTime())
				.getAdjustment(), 3);

	}

	@Test
	public void getInvalidDate() {
		// nulls
		Date di = null;
		Assert.assertEquals(baseCalendar.getWorkingTime(di), 0, "null DateIndex");

		Calendar cal = null;
		Assert.assertEquals(baseCalendar.getWorkingTime(null), 0, "null Calendar");

		// This should just return right amount for day of week (in this case
		// Friday)
		cal = new Q3Calendar();
		cal.set(2014, 11, 12);
		di = cal.getTime();
		Assert.assertEquals(baseCalendar.getWorkingTime(di), 420, "big di");

		cal = GregorianCalendar.getInstance();
		cal.add(Calendar.YEAR, 7);
		cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
		Assert.assertEquals(baseCalendar.getWorkingTime(cal.getTime()), 420, "big Calendar");
	}

	@Test
	public void getWorkingTime() {
		// Make Jan 1st and 2nd as bank holidays (0 in base calendar)
		// Also make Jan 3 a part day (200)
		baseCalendar.addAdjustment(2008, 0, 1, true, 0);
		baseCalendar.addAdjustment(2008, 0, 2, true, 0);
		baseCalendar.addAdjustment(2008, 0, 3, true, 200);
		// for rc1 make no adjustments

		// for rc2 make an absolute adj to Jan 2 to make it 300
		// a relative adj to make Jan 3 350 (+150)
		// a rel adj to Jan 4 to make it 400 (-20)
		resourceCalendar2.addAdjustment(2008, 0, 2, true, 300);
		resourceCalendar2.addAdjustment(2008, 0, 3, false, 150);
		resourceCalendar2.addAdjustment(2008, 0, 4, false, -20);

		// r1 should reflect base settings, including adjustments
		Q3Calendar cal = new Q3Calendar();
		cal.setTimeInMillis(0);
		cal.set(2008, 0, 1);
		Assert.assertEquals(resourceCalendar1.getWorkingTime(cal.getTime()), 0);
		cal.incDay();
		Assert.assertEquals(resourceCalendar1.getWorkingTime(cal.getTime()), 0);
		cal.incDay();
		Assert.assertEquals(resourceCalendar1.getWorkingTime(cal.getTime()), 200);
		cal.incDay();
		Assert.assertEquals(resourceCalendar1.getWorkingTime(cal.getTime()), 420);

		// r2 should combine the base and resource settings
		cal.set(2008, 0, 1);
		Assert.assertEquals(resourceCalendar2.getWorkingTime(cal.getTime()), 0);
		cal.incDay();
		Assert.assertEquals(resourceCalendar2.getWorkingTime(cal.getTime()), 300);
		cal.incDay();
		Assert.assertEquals(resourceCalendar2.getWorkingTime(cal.getTime()), 350);
		cal.incDay();
		Assert.assertEquals(resourceCalendar2.getWorkingTime(cal.getTime()), 400);

	}

	@Test
	public void minutesToDays() {
		DefaultWorkingTime dwt = new DefaultWorkingTime();
		Calendar cal = new GregorianCalendar();
		// this is a Monday
		cal.set(2008, 07, 11, 0, 0, 0);
		int minutes = dwt.getTime(Calendar.MONDAY);
		double days = baseCalendar.minutesToWorkingDays(minutes, cal.getTime());
		Assert.assertEquals(days, 1.0);

		minutes = dwt.getTime(Calendar.MONDAY) / 2;
		days = baseCalendar.minutesToWorkingDays(minutes, cal.getTime());
		Assert.assertEquals(days, 0.5);

		minutes = dwt.getTime(Calendar.MONDAY);
		minutes = minutes + (dwt.getTime(Calendar.TUESDAY));
		days = baseCalendar.minutesToWorkingDays(minutes, cal.getTime());
		Assert.assertEquals(days, 2.0);

		minutes = dwt.getTime(Calendar.MONDAY);
		minutes = minutes + ((dwt.getTime(Calendar.TUESDAY)) / 2);
		days = baseCalendar.minutesToWorkingDays(minutes, cal.getTime());
		Assert.assertEquals(days, 1.5);
	}
}
